/*  This file is Copyright 2010 Hampton Smith
 * 
 *  This file is part of Adventure! a text-adventure game engine by Hampton
 *  Smith.
 *
 *  Adventure! is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Adventure! is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Adventure!.  If not, see http://www.gnu.org/licenses/.
 */


package edu.clemson.cs.hamptos.adventure;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;

/**
 * <p>An <code>AdventureWindow</code> is a graphical interface for navigating a
 * given adventure.  It is also the entry-point for the game engine.  By
 * creating a new <code>AdventureWindow</code> with a
 * <code>AdventureLocation</code> and a <code>AdventureParser</code> you can
 * play through the adventure you've created.</p>
 */
public class AdventureWindow {

    private static final String ISSUE_ACTION = "Issue";

    private final JTerminalDisplay myTerminal = new JTerminalDisplay();
    private final JTextField myInputArea = new JTextField();

    public final AdventureEngine myEngine;

    /**
     * <p>Creates a new <code>AdventureWindow</code>, with the player beginning
     * at <code>startLocation</code> and all input parsed by
     * <code>parsingStrategy</code>.  The window is shown immediately with the
     * title text given in <code>titlebar</code>.</p>
     * 
     * @param titlebar        The text to display in the window's titlebar.
     * @param startLocation   The location where the player starts.
     * @param parsingStrategy The parsing strategy to apply to input.
     */
    public AdventureWindow(String titlebar, AdventureLocation startLocation,
            AdventureParser parsingStrategy) {

        JFrame window = new JFrame();
        try
        {
            window.setIconImage(ImageIO.read(new File("UmbCorpImgedit.png")));
        }
        catch (Exception ex)
        {
            //suppress the image load error, not imperative to handle
        }
        myEngine = new AdventureEngine(this, parsingStrategy, startLocation);

        //Lets look nice on any screen
        Dimension screenSize = getScreenSize();
        int width = Math.max(600, Math.min(800, screenSize.width));
        int height = Math.max(300, Math.min(600, screenSize.height));

        window.setSize(width, height);
        window.setTitle(titlebar);

        //What to do if the user presses the X button?
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Add a couple custom actions for things like "pressing enter"
        initializeInput();

        JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
                myTerminal, myInputArea);

        window.add(split);
        window.setVisible(true);
    }

    /**
     * <p>Creates a new <code>AdventureWindow</code>, with the player beginning
     * at <code>startLocation</code> and all input parsed by
     * <code>parsingStrategy</code>.  The window is show immediately with
     * some default title text.</p>
     *
     * @param startLocation   The location where the player starts.
     * @param parsingStrategy The parsing strategy to apply to input.
     */
    public AdventureWindow(AdventureLocation startLocation,
            AdventureParser parsingStrategy) {

        this("A Freaking Awesome Text Adventure", startLocation,
                parsingStrategy);
    }

    /**
     * <p>Turns debug mode on or off.  When debug mode is on, debug statements
     * are printed on certain events, such as when an item is added to a
     * player's inventory.</p>
     *
     * @param debug <code>true</code> if debug mode should be on.
     */
    public void setDebugMode(boolean debug) {
        myEngine.setDebugMode(debug);
    }

    private void initializeInput() {

        //We build a custom input map
        InputMap originalInput = myInputArea.getInputMap();
        InputMap customInput = new InputMap();
        customInput.setParent(originalInput);
        myInputArea.setInputMap(JComponent.WHEN_FOCUSED, customInput);

        //And a custom action map
        ActionMap originalAction = myInputArea.getActionMap();
        ActionMap customAction = new ActionMap();
        customAction.setParent(originalAction);
        myInputArea.setActionMap(customAction);

        //Add an action to our custom action map that executes the command
        //and highlights all the text, call it ISSUE_ACTION
        customAction.put(ISSUE_ACTION, new IssueAction());

        //When the user presses enter, perform the IssueAction set up above
        customInput.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
                ISSUE_ACTION);
    }

    /**
     * <p>Prints a line of text to the terminal of this window.  The given
     * <code>text</code> is interpreted as HTML and a newline is automatically
     * appended to the end.</p>
     *
     * @param text HTML to be added to the terminal.
     */
    public void println(String text) {
        //Newlines won't show up properly--in HTML we break with <br/>
        text = text.replace("\n", "<br/>");

        myTerminal.println(text);
    }

    private static Dimension getScreenSize() {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        return toolkit.getScreenSize();
    }

    private class IssueAction extends AbstractAction {

        public IssueAction() {
            super(ISSUE_ACTION);
        }

        public void actionPerformed(ActionEvent e) {
            if (myInputArea.getText().length() > 0) {
                myEngine.doCommand(myInputArea.getText());
                myInputArea.selectAll();
            }
        }
    }
}
